package com.wang.template.json;

import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.wang.template.json.core.Keys;
import com.wang.template.json.core.TemplateUtils;
import com.wang.template.json.node.ArrayNode;
import com.wang.template.json.node.BaseNode;
import com.wang.template.json.node.NodeType;
import com.wang.template.json.node.ObjectNode;
import com.wang.template.json.node.StringNode;
import com.wang.template.json.util.UtilExt;

public class JsonLoader {

	/**
	 * 读取json模板，这块可以工程启动完毕就加载</br>
	 * 然后缓存起来,静态调用<br>
	 */
	public static BaseNode load(String jsonStr) throws Exception {
		if (StringUtils.isBlank(jsonStr)) {
			return null;
		}
		jsonStr = jsonStr.trim();
		Object root = null;
		if (TemplateUtils.isJsonArray(jsonStr)) {
			root = JSON.parseArray(jsonStr);
		} else {
			root = JSON.parseObject(jsonStr);
		}
		return loadJson(root);
	}

	private static BaseNode loadJson(Object json) throws Exception {
		if (json instanceof String) {
			return buildStringNode(json);
		} else if (json instanceof JSONArray) {
			return buildArrayNode(json);
		} else if (json instanceof JSONObject) {
			return buildObjectNode(json);
		}
		return null;
	}

	private static StringNode buildStringNode(Object json) {
		StringNode strNode = new StringNode();
		strNode.setType(NodeType.STRING);
		strNode.setDs(TemplateUtils.buildDataSource(String.valueOf(json)));
		return strNode;
	}

	private static ObjectNode buildObjectNode(Object json) throws Exception {
		ObjectNode objNode = new ObjectNode();
		objNode.setType(NodeType.OBJECT);
		JSONObject jsonObj = (JSONObject) json;
		JSONObject metaInfo = jsonObj.getJSONObject(Keys.DATA_MEAT);
		if (metaInfo != null) {
			cacheBeanInfo(metaInfo.getString(Keys.BEAN_TYPE));
			// 没有配置数据源表示这是最外层的对象
			String dataSource = metaInfo.getString(Keys.DATA_SOURCE);
			objNode.setDs(TemplateUtils.buildDataSource(dataSource));
			jsonObj.remove(Keys.DATA_MEAT);
		}
		if (jsonObj.entrySet().size() > 0) {
			Map<String, BaseNode> mapRules = new HashMap<String, BaseNode>();
			for (Map.Entry<String, Object> entity : jsonObj.entrySet()) {
				String key = entity.getKey();
				Object value = entity.getValue();
				mapRules.put(key, loadJson(value));
			}
			objNode.setMap(mapRules);
		} else {
			objNode.setMap(null);
		}
		return objNode;
	}

	private static ArrayNode buildArrayNode(Object json) throws Exception {
		ArrayNode arrayNode = new ArrayNode();
		arrayNode.setType(NodeType.ARRAY);
		JSONObject arrayConf = ((JSONArray) json).getJSONObject(0);
		JSONObject metaInfo = (JSONObject) arrayConf.remove(Keys.DATA_MEAT);
		ObjectNode mapRules = ((ObjectNode) loadJson(arrayConf));
		arrayNode.setMap((mapRules == null || mapRules.getMap() == null || mapRules.getMap().size() == 0) ? null
				: mapRules.getMap());
		if (metaInfo == null) {
			throw new RuntimeException("数组映射请指定元信息");
		}
		String dataSource = metaInfo.getString(Keys.DATA_SOURCE);
		if (StringUtils.isBlank(dataSource)) {
			throw new RuntimeException("数组映射ds信息未指定");
		}
		arrayNode.setDs(TemplateUtils.buildDataSource(dataSource));
		cacheBeanInfo(metaInfo.getString(Keys.BEAN_TYPE));
		return arrayNode;
	}

	private static void cacheBeanInfo(String beans) throws Exception {
		if (StringUtils.isBlank(beans)) {
			return;
		}
		for (String bean : JSON.parseArray(beans, String.class)) {
			if (StringUtils.isBlank(bean)) {
				continue;
			}
			Class<?> beanClass = Class.forName(bean);
			UtilExt.addMethodAccess(beanClass);
		}
	}
}
